package httpclient

import (
	"encoding/json"
	"github.com/go-resty/resty/v2"
	"io"
	"net/http"
	"time"
)

type HttpClient struct {
	client         *resty.Client
	mapTestTraffic map[string]string
}

type Context interface {
	GetStringMapString(string) map[string]string
}

type URLSetting struct {
	RetryCount int           `mapstructure:"retry_count"`
	Timeout    time.Duration `mapstructure:"timeout"`
	// ErrHook 用于用户自定义http调用报错时要做的处理
	ErrHook resty.ErrorHook
}

// New 完全版new，适合修改重试次数时或默认超时时间时
func New(setting URLSetting) *HttpClient {
	if setting.Timeout == 0 {
		setting.Timeout = 2 * time.Second
	}

	c := resty.New()

	c.RetryCount = setting.RetryCount

	c.SetTimeout(setting.Timeout)

	if setting.ErrHook != nil {
		c.OnError(setting.ErrHook)
	}

	return &HttpClient{
		client: c,
	}
}

// QuickNew 简易版使用，直接请求
func QuickNew() *HttpClient {
	c := resty.New()
	c.SetTimeout(2 * time.Second)

	return &HttpClient{
		client: c,
	}
}

func (c *HttpClient) SetHeaders(headers map[string]string) *HttpClient {
	c.client.SetHeaders(headers)
	return c
}

func (c *HttpClient) SetProxy(proxyURL string) *HttpClient {
	c.client.SetProxy(proxyURL)
	return c
}

func (c *HttpClient) SetCookie(cookies map[string]string) *HttpClient {
	var cookies_ = make([]*http.Cookie, 0, len(cookies))
	for k, v := range cookies {
		cookies_ = append(cookies_, &http.Cookie{
			Name:  k,
			Value: v,
		})
	}
	c.client.SetCookies(cookies_)
	return c
}

func (c *HttpClient) Get(url string, params map[string]string) (res []byte, err error) {
	response, err := c.client.R().SetQueryParams(params).Get(url)
	if err != nil {
		return
	}
	res = response.Body()
	return
}

func (c *HttpClient) GetByRes(url string, params map[string]string, result interface{}) (response *resty.Response, err error) {
	response, err = c.client.R().SetQueryParams(params).SetResult(result).Get(url)
	return
}

func (c *HttpClient) PostJson(url string, params interface{}) (response *resty.Response, err error) {
	c.client.SetHeader("Content-Type", "application/json")
	jsonData, _ := json.Marshal(params)
	response, err = c.client.R().SetBody(jsonData).Post(url)
	return
}

func (c *HttpClient) PostJsonByRes(url string, params, result interface{}) (response *resty.Response, err error) {
	c.client.SetHeader("Content-Type", "application/json")
	jsonData, _ := json.Marshal(params)
	response, err = c.client.R().SetBody(jsonData).SetResult(result).Post(url)
	return
}

func (c *HttpClient) PostForm(url string, params map[string]string) (response *resty.Response, err error) {
	response, err = c.client.R().SetFormData(params).Post(url)
	return
}

func (c *HttpClient) PostFormByRes(url string, params map[string]string, result interface{}) (response *resty.Response, err error) {
	response, err = c.client.R().SetFormData(params).SetResult(result).Post(url)
	return
}

type FileParam struct {
	Key        string
	FileName   string
	FileReader io.Reader
}

func (c *HttpClient) PostFile(url string, params map[string]string, files []FileParam) (response *resty.Response, err error) {
	r := c.client.R().SetFormData(params)
	for i := 0; i < len(files); i++ {
		r = r.SetFileReader(files[i].Key, files[i].FileName, files[i].FileReader)
	}
	response, err = r.Post(url)
	return
}

func (c *HttpClient) PostFileByRes(url string, params map[string]string, files []FileParam, result interface{}) (response *resty.Response, err error) {
	r := c.client.R().SetFormData(params)
	for i := 0; i < len(files); i++ {
		r = r.SetFileReader(files[i].Key, files[i].FileName, files[i].FileReader)
	}
	response, err = r.SetResult(result).Post(url)
	return
}
